Part 3: Add some testing for a=end-of-candidates in remote SDP. Differential Revision: https://phabricator.services.mozilla.com/D23591 bugzilla-url: https://bugzilla.mozilla.org/show_bug.cgi?id=1318167 gecko-commit: b425ca25edc52da94ae2fc65a571ea054c46ac4f gecko-integration-branch: central gecko-reviewers: end-of-candidates, jib 
diff --git a/webrtc/RTCPeerConnection-addIceCandidate.html b/webrtc/RTCPeerConnection-addIceCandidate.html index 7a09885..51a5677 100644 --- a/webrtc/RTCPeerConnection-addIceCandidate.html +++ b/webrtc/RTCPeerConnection-addIceCandidate.html 
@@ -85,28 +85,35 @@  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');  }   - // Check that a candidate line is found after the first media line - // but before the second, i.e. it belongs to the first media stream - function assert_candidate_line_between(sdp, beforeMediaLine, candidateLine, afterMediaLine) { + function is_candidate_line_between(sdp, beforeMediaLine, candidateLine, afterMediaLine) {  const line1 = escapeRegExp(beforeMediaLine);  const line2 = escapeRegExp(candidateLine);  const line3 = escapeRegExp(afterMediaLine);    const regex = new RegExp(`${line1}[^]+${line2}[^]+${line3}`); + return regex.test(sdp); + }   - assert_true(regex.test(sdp), + // Check that a candidate line is found after the first media line + // but before the second, i.e. it belongs to the first media stream + function assert_candidate_line_between(sdp, beforeMediaLine, candidateLine, afterMediaLine) { + assert_true(is_candidate_line_between(sdp, beforeMediaLine, candidateLine, afterMediaLine),  `Expect candidate line to be found between media lines ${beforeMediaLine} and ${afterMediaLine}`);  }    // Check that a candidate line is found after the second media line  // i.e. it belongs to the second media stream - function assert_candidate_line_after(sdp, beforeMediaLine, candidateLine) { + function is_candidate_line_after(sdp, beforeMediaLine, candidateLine) {  const line1 = escapeRegExp(beforeMediaLine);  const line2 = escapeRegExp(candidateLine);    const regex = new RegExp(`${line1}[^]+${line2}`);   - assert_true(regex.test(sdp), + return regex.test(sdp); + } + + function assert_candidate_line_after(sdp, beforeMediaLine, candidateLine) { + assert_true(is_candidate_line_after(sdp, beforeMediaLine, candidateLine),  `Expect candidate line to be found after media line ${beforeMediaLine}`);  }   @@ -133,30 +140,35 @@  /*  Success cases  */ - // The RTCIceCandidateInit arg to addIceCandidate is optional, and is converted - // to the default RTCIceCandidateInit. Then, because the default candidate is - // "", addIceCandidate will allow both sdpMid and sdpMLineIndex to be absent. - promise_test(async t => { + + // All of these should work, because all of these end up being equivalent to the + // same thing; an end-of-candidates signal for all levels/mids/ufrags. + [ + // This is just the default. Everything else here is equivalent to this. + { + candidate: '', + sdpMid: null, + sdpMLineIndex: null, + usernameFragment: undefined + }, + // The arg is optional, so when passing undefined we'll just get the default + undefined, + // The arg is optional, but not nullable, so we get the default again + null, + // Members in the dictionary take their default values + {} + ].forEach(init => promise_test(async t => {  const pc = new RTCPeerConnection();    t.add_cleanup(() => pc.close());    await pc.setRemoteDescription(sessionDesc);  await pc.addIceCandidate(); - }, 'addIceCandidate() should work'); - - // The RTCIceCandidateInit arg to addIceCandidate is optional, and not - // nullable, so null is converted to the default RTCIceCandidateInit. Then, - // because the default candidate is "", addIceCandidate will allow both - // sdpMid and sdpMLineIndex to be absent. - promise_test(async t => { - const pc = new RTCPeerConnection(); - - t.add_cleanup(() => pc.close()); - - await pc.setRemoteDescription(sessionDesc); - await pc.addIceCandidate(null); - }, 'Add null candidate should work'); + assert_candidate_line_between(pc.remoteDescription.sdp, + mediaLine1, endOfCandidateLine, mediaLine2); + assert_candidate_line_after(pc.remoteDescription.sdp, + mediaLine2, endOfCandidateLine); + }, `addIceCandidate(${JSON.stringify(init)}) should work, and add a=end-of-candidates to both m-sections`));    promise_test(async t => {  const pc = new RTCPeerConnection(); @@ -164,8 +176,12 @@  t.add_cleanup(() => pc.close());    await pc.setRemoteDescription(sessionDesc); - await pc.addIceCandidate({}); - }, 'Add candidate with empty dict should work'); + await pc.addIceCandidate({usernameFragment: usernameFragment1}); + assert_candidate_line_between(pc.remoteDescription.sdp, + mediaLine1, endOfCandidateLine, mediaLine2); + assert_false(is_candidate_line_after(pc.remoteDescription.sdp, + mediaLine2, endOfCandidateLine)); + }, 'addIceCandidate({usernameFragment: usernameFragment1}) should work, and add a=end-of-candidates to the first m-section');    promise_test(async t => {  const pc = new RTCPeerConnection(); @@ -173,13 +189,25 @@  t.add_cleanup(() => pc.close());    await pc.setRemoteDescription(sessionDesc); - await pc.addIceCandidate({ - candidate: '', - sdpMid: null, - sdpMLineIndex: null, - usernameFragment: undefined - }); - }, 'Add candidate with manually filled default values should work'); + await pc.addIceCandidate({usernameFragment: usernameFragment2}); + assert_false(is_candidate_line_between(pc.remoteDescription.sdp, + mediaLine1, endOfCandidateLine, mediaLine2)); + assert_true(is_candidate_line_after(pc.remoteDescription.sdp, + mediaLine2, endOfCandidateLine)); + }, 'addIceCandidate({usernameFragment: usernameFragment2}) should work, and add a=end-of-candidates to the first m-section'); + + promise_test(async t => { + const pc = new RTCPeerConnection(); + + t.add_cleanup(() => pc.close()); + + await pc.setRemoteDescription(sessionDesc); + await pc.addIceCandidate({usernameFragment: "no such ufrag"}); + assert_false(is_candidate_line_between(pc.remoteDescription.sdp, + mediaLine1, endOfCandidateLine, mediaLine2)); + assert_false(is_candidate_line_after(pc.remoteDescription.sdp, + mediaLine2, endOfCandidateLine)); + }, 'addIceCandidate({usernameFragment: "no such ufrag"}) should work, but not add a=end-of-candidates');    promise_test(t => {  const pc = new RTCPeerConnection();